/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { ClassDeclaration, SourceFile } from 'ts-morph';
import { ClassAnalysis, ClassDetails, Logger, PropertyAnalysis, PropertyKind, TypeKind, TypeStructure } from '../../..';
import { ImportManager } from '../shared/ImportManager';
import { ClassAnalyzer } from '../../../analyzers/ClassAnalyzer';
import { TypeHandlerRegistry } from '../../../handlers';
import { ConversionDirection } from '../../../handlers/ITypeHandler';
import { TsMorphUtil } from '../../../utils/TsMorphUtil';
import SerializationPathUtil from '../../../utils/SerializationPathUtil';

export class SendableClassGenerator {
  canHandle(result: ClassAnalysis): boolean {
    return !!result.decorators.serializable?.generateSendable;
  }

  generate(sourceFile: SourceFile, result: ClassAnalysis, importManager: ImportManager): void {
    // 1. 复制原始类结构
    const sendableClass = this.getOriginClassDeclaration(result);

    // 2. 修改类名
    this.renameSendableClass(sendableClass, result);

    // 3. 修改继承的类名
    this.updateInheritanceToSendable(sendableClass, result);

    // 4.移除实现关系，否则会出现属性类型变化，但是接口定义类型未修改情况
    this.removeImplements(sendableClass);

    // 4. 剔除所有装饰器
    this.removeAllDecorators(sendableClass);

    // 5. 转换属性类型
    this.convertPropertyTypesToSendable(sendableClass, result);

    // 6. 转换构造函数参数类型
    this.convertConstructorParameterTypes(sendableClass, result);

    // 7. 添加@Sendable装饰器和lang.ISendable接口
    this.addSendableConstraints(sendableClass);

    // 8. 添加toOrigin方法
    this.addToOriginMethod(sendableClass, result, importManager);

    // 9. 添加必要地导入语句
    this.addNecessaryImports(result, importManager);

    // 10. 将处理后的类添加到目标文件
    sourceFile.addClasses([sendableClass.getStructure()]);
  }

  private getOriginClassDeclaration(result: ClassAnalysis): ClassDeclaration {
    const originalContent = result.originalClass?.getFullText();
    const copiedSourceFile = TsMorphUtil.getProject().createSourceFile('copied-file.ts', originalContent, { overwrite: true });
    return copiedSourceFile.getClassOrThrow(result.className);
  }

  private renameSendableClass(classDecl: ClassDeclaration, result: ClassAnalysis): void {
    const sendableClassName = this.getSendableClassName(result);
    classDecl.set({ name: sendableClassName });
  }

  private updateInheritanceToSendable(classDecl: ClassDeclaration, result: ClassAnalysis): void {
    if (!result.inheritance.isInherited) {
      return;
    }
    const extendsClause = classDecl.getExtendsOrThrow();
    const sendableBaseClassName = `Sendable${result.inheritance.baseClassAnalysis?.className}`;
    extendsClause.setExpression(sendableBaseClassName);
  }

  private removeImplements(classDecl: ClassDeclaration): void {
    const implementsClauses = classDecl.getImplements();
    implementsClauses.forEach(imple => {
      classDecl.removeImplements(imple);
    });
  }

  private removeAllDecorators(classDecl: ClassDeclaration): void {
    // 剔除类级别装饰器
    classDecl.getDecorators().forEach((decorator) => {
      Logger.warn(
        `Remove the decorator ${decorator.getName()}, because @Sendable cannot coexist with other decorators`
      );
      decorator.remove();
    });

    // 剔除属性装饰器，@Sendable无法与其他装饰器共存
    classDecl.getProperties().forEach((property) => {
      property.getDecorators().forEach((decorator) => {
        Logger.warn(
          `Remove the decorator ${decorator.getName()}, because @Sendable cannot coexist with other decorators`
        );
        decorator.remove();
      });
    });

    // 剔除方法装饰器，@Sendable无法与其他装饰器共存
    classDecl.getMethods().forEach((method) => {
      method.getDecorators().forEach((decorator) => {
        Logger.warn(
          `Remove the decorator ${decorator.getName()}, because @Sendable cannot coexist with other decorators`
        );
        decorator.remove();
      });
    });
  }

  private convertPropertyTypesToSendable(classDecl: ClassDeclaration, result: ClassAnalysis): void {
    const properties = classDecl.getProperties();

    properties.forEach((property) => {
      const propertyName = property.getName();

      Logger.debug(`Converting property ${propertyName} to sendable`);

      // 从分析结果中找到对应的属性信息
      const propertyAnalysis = result.properties.find((p) => p.name === propertyName);
      if (!propertyAnalysis) {
        Logger.warn(`未找到属性 ${propertyName} 的分析信息`);
        return;
      }

      Logger.debug(
        `Found property ${propertyName} analysis info: ${propertyAnalysis.name} ${propertyAnalysis.type.sourceText}`
      );

      // 转换类型为Sendable兼容类型
      const sendableType = this.convertToSendableType(propertyAnalysis.type);

      Logger.debug(`Converted type ${propertyAnalysis.type.sourceText} to ${sendableType}`);

      if (sendableType !== propertyAnalysis.type.sourceText) {
        property.setType(sendableType);
        Logger.debug(`属性 ${propertyName} 类型从 ${propertyAnalysis.type.sourceText} 转换为 ${sendableType}`);
      }

      // 处理默认值中的构造函数调用
      const initializer = property.getInitializer();
      if (initializer) {
        const initializerText = initializer.getText();
        const convertedInitializer = this.convertInitializerToSendable(initializerText);
        if (convertedInitializer !== initializerText) {
          property.setInitializer(convertedInitializer);
          Logger.debug(`属性 ${propertyName} 默认值从 ${initializerText} 转换为 ${convertedInitializer}`);
        }
      }
    });
  }

  private addSendableConstraints(classDecl: ClassDeclaration): void {
    // 添加@Sendable装饰器
    classDecl.addDecorator({ name: 'Sendable' });

    // 实现lang.ISendable接口
    classDecl.addImplements('lang.ISendable');
  }

  private addToOriginMethod(classDecl: ClassDeclaration, result: ClassAnalysis, importManger: ImportManager): void {
    let returnType = result.className;
    if (result.generics.isGeneric) {
      returnType += `<${result.generics.parameters.join(', ')}>`;
    }
    const methodBody = this.generatedToOriginMethodBody(result, returnType);
    classDecl.addMethod({
      name: 'toOrigin',
      returnType,
      statements: [methodBody]
    });

    // 导入原始类
    importManger.registerCustomTypeImport(result.sourceFilePath, result.className);
  }

  private generatedToOriginMethodBody(result: ClassAnalysis, returnType: string): string {
    const statements: string[] = [];
    let constructorCall;
    if (result.constructorParams.length > 0) {
      const constructorProps: PropertyAnalysis[] = [];
      result.properties.forEach((p) => {
        const isConstructorProp = result.constructorParams.find((cp) => cp.name === p.name);
        if (isConstructorProp) {
          constructorProps.push({
            ...p,
            type: {
              ...p.type,
              isOptional: isConstructorProp.isOptional
            }
          });
        }
      });

      const args = constructorProps
        .map((prop) => {
          return this.generatePropertyConversion(prop, 'this.');
        })
        .join(', ');

      constructorCall = `new ${returnType}(${args})`;
    } else {
      constructorCall = `new ${returnType}()`;
    }
    statements.push(`const origin = ${constructorCall};`);

    const assignmentProps = result.properties.filter((p) => {
      return result.constructorParams.every((cp) => cp.name !== p.name);
    });
    // 生成属性赋值语句
    if (assignmentProps.length > 0) {
      statements.push('');
      statements.push('// 非构造函数属性赋值');
      assignmentProps.forEach((prop) => {
        const assignment = this.generatePropertyConversion(prop, 'this.');
        statements.push(`origin.${prop.name} = ${assignment};`);
      });
    }

    statements.push('');
    statements.push('return origin;');

    return statements.join('\n');
  }

  private generatePropertyConversion(prop: PropertyAnalysis, prefix: string): string {
    const sourceValue = `${prefix}${prop.name}`;
    if (prop.type.kind === PropertyKind.UNKNOWN) {
      // UNKNOWN只接跳过
      return sourceValue;
    }
    const registry = TypeHandlerRegistry.getInstance();
    const handler = registry.getHandlerForKind(prop.type.kind);

    try {
      // TO_ORIGIN: Sendable对象 -> 普通对象
      return handler.generatePropertyConversion(prop.type, sourceValue, ConversionDirection.TO_ORIGIN);
    } catch (error) {
      Logger.error(`生成属性转换代码失败: ${error}`);
      return sourceValue;
    }
  }

  private getSendableClassName(result: ClassAnalysis): string {
    return `Sendable${result.className}`;
  }

  private addNecessaryImports(result: ClassAnalysis, importManager: ImportManager): void {
    // 1. 处理类导入
    result.properties.forEach((property) => {
      property.type.dependencies.forEach((dependency) => {
        if (dependency.typeKind === TypeKind.CLASS) {
          const classAnalysis = ClassAnalyzer.analyzeClass((dependency.details as ClassDetails).classDecl);
          if (classAnalysis.decorators.serializable?.generateSendable) {
            importManager.registerCustomImport('./Sendable' + dependency.typeName, 'Sendable' + dependency.typeName);
          } else {
            importManager.registerCustomTypeImport(dependency.source.sourceFilePath!, dependency.typeName);
          }
        } else {
          importManager.registerCustomTypeImport(dependency.source.sourceFilePath!, dependency.typeName);
        }
      });
    });

    const baseClass = result.inheritance.baseClassAnalysis;
    if (baseClass) {
      importManager.registerCustomImport('./Sendable' + baseClass.className, 'Sendable' + baseClass.className);
    }
    // 2. 检查是否需要collections导入
    const needsCollections = this.needsCollectionsImport(result);
    if (needsCollections) {
      importManager.registerArkTSImports(['collections']);
    }
    // 3. 拷贝源文件导入
    result.originalClass?.getSourceFile().getImportDeclarations().forEach(importDecl => {
      const specifier = importDecl.getModuleSpecifierValue();
      const names = importDecl.getNamedImports().map((names) => names.getName());
      const defaultImport = importDecl.getDefaultImport();
      const originalDir = SerializationPathUtil.dirname(result.sourceFilePath);

      const importOriginAbs = SerializationPathUtil.pathResolve(originalDir, specifier);
      if (SerializationPathUtil.exist(importOriginAbs + '.ets')) {
        // 路径存在，使用模块化路径计算
        const importOriginAbsWithExt = importOriginAbs + '.ets';
        names.forEach((name) => {
          importManager.registerCustomTypeImport(importOriginAbsWithExt, name);
        });
        if (defaultImport) {
          importManager.registerDefaultImport(importOriginAbsWithExt, defaultImport.getText());
        }
      } else {
        // 不存在该路径，说明可能为包名，暂时不动
        names.forEach((name) => {
          importManager.registerCustomImport(specifier, name);
        });
        if (defaultImport) {
          importManager.registerDefaultImport(specifier, defaultImport.getText());
        }
      }
    });
  }

  private convertConstructorParameterTypes(classDecl: ClassDeclaration, result: ClassAnalysis): void {
    const constructors = classDecl.getConstructors();

    constructors.forEach((constructor) => {
      const parameters = constructor.getParameters();

      parameters.forEach((parameter) => {
        const paramName = parameter.getName();

        // 从分析结果中找到对应的属性信息
        const propertyAnalysis = result.properties.find((p) => p.name === paramName);
        if (!propertyAnalysis) {
          Logger.warn(`未找到构造函数参数 ${paramName} 的分析信息`);
          return;
        }

        // 转换参数类型为Sendable兼容类型
        const sendableType = this.convertToSendableType(propertyAnalysis.type);
        if (sendableType !== propertyAnalysis.type.sourceText) {
          parameter.setType(sendableType);
          Logger.debug(`构造函数参数 ${paramName} 类型从 ${propertyAnalysis.type.sourceText} 转换为 ${sendableType}`);
        }
      });
    });
  }

  private isObjectType(typeName: string): boolean {
    // 基础类型不需要转换
    const primitiveTypes = ['string', 'number', 'boolean', 'bigint', 'null', 'undefined'];
    if (primitiveTypes.includes(typeName)) {
      return false;
    }

    // 集合类型不需要转换（已经处理过）
    if (
      typeName.startsWith('collections.') ||
      typeName.startsWith('Array<') ||
      typeName.startsWith('Map<') ||
      typeName.startsWith('Set<')
    ) {
      return false;
    }

    // 已经是Sendable类型的不需要再转换
    if (typeName.startsWith('Sendable')) {
      return false;
    }

    // 其他情况认为是对象类型，需要转换
    return true;
  }

  public needsCollectionsImport(result: ClassAnalysis): boolean {
    return result.properties.some((prop) => {
      const typeText = this.convertToSendableType(prop.type);
      return typeText.includes('collections');
    });
  }

  private convertInitializerToSendable(initializerText: string): string {
    let convertedText = initializerText;

    // 1. 处理数组字面量（最优先）
    if (convertedText === '[]') {
      convertedText = 'new collections.Array()';
    } else if (convertedText.startsWith('[') && convertedText.endsWith(']')) {
      // 处理 [1, 2, 3] 这种情况
      const arrayContent = convertedText.slice(1, -1);
      if (arrayContent.trim()) {
        convertedText = `new collections.Array(${arrayContent})`;
      } else {
        convertedText = 'new collections.Array()';
      }
    }

    // 2. 处理集合类型构造函数（优先于对象类型）
    convertedText = convertedText.replace(/new\s+Set\s*\(/g, 'new collections.Set(');
    convertedText = convertedText.replace(/new\s+Map\s*\(/g, 'new collections.Map(');
    convertedText = convertedText.replace(/new\s+Array\s*\(/g, 'new collections.Array(');

    // 3. 处理对象构造函数：new Person(...) -> new SendablePerson(...)
    const objectConstructorPattern = /new\s+(\w+)\s*\(/g;
    convertedText = convertedText.replace(objectConstructorPattern, (match, className) => {
      // 跳过已经转换的集合类型
      if (className === 'collections' || match.includes('collections.')) {
        return match;
      }

      if (this.isObjectType(className)) {
        return match.replace(className, `Sendable${className}`);
      }
      return match;
    });

    Logger.debug(`初始化器转换: ${initializerText} -> ${convertedText}`);
    return convertedText;
  }

  private convertToSendableType(structure: TypeStructure): string {
    if (structure.kind === PropertyKind.UNKNOWN) {
      // UNKNOWN只接跳过
      return structure.sourceText;
    }
    const registry = TypeHandlerRegistry.getInstance();
    const handler = registry.getHandlerForKind(structure.kind);
    return handler.generateSendableTypeDeclaration(structure);
  }
}
